<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>Have fun with glibc内存管理 | o0xmuhe&#39;s blog</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="使用的源码版本 glibc-2.24 持续更新，治疗拖延症。">
<meta name="keywords" content="glibc内存管理">
<meta property="og:type" content="article">
<meta property="og:title" content="Have fun with glibc内存管理">
<meta property="og:url" content="http:&#x2F;&#x2F;o0xmuhe.me&#x2F;2016&#x2F;11&#x2F;21&#x2F;Have-fun-with-glibc%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86&#x2F;index.html">
<meta property="og:site_name" content="o0xmuhe&#39;s blog">
<meta property="og:description" content="使用的源码版本 glibc-2.24 持续更新，治疗拖延症。">
<meta property="og:locale" content="default">
<meta property="og:updated_time" content="2016-11-25T09:45:59.000Z">
<meta name="twitter:card" content="summary">
  
    <link rel="alternative" href="/atom.xml" title="o0xmuhe&#39;s blog" type="application/atom+xml">
  
  
    <link rel="icon" href="/img/favicon.png">
  
  
      <link rel="stylesheet" href="//cdn.bootcss.com/animate.css/3.5.0/animate.min.css">
  
  <link rel="stylesheet" href="/css/style.css">
  <link rel="stylesheet" href="/font-awesome/css/font-awesome.min.css">
  <link rel="apple-touch-icon" href="/apple-touch-icon.png">
  
  
      <link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
  
  <!-- 加载特效 -->
    <script src="/js/pace.js"></script>
    <link href="/css/pace/pace-theme-flash.css" rel="stylesheet" />
  <script>
      var yiliaConfig = {
          rootUrl: '/',
          fancybox: true,
          animate: true,
          isHome: false,
          isPost: true,
          isArchive: false,
          isTag: false,
          isCategory: false,
          open_in_new: false
      }
  </script>
</head>
<body>
  <div id="container">
    <div class="left-col">
    <div class="overlay"></div>
<div class="intrude-less">
    <header id="header" class="inner">
        <a href="/" class="profilepic">
            
            <img lazy-src="/img/head.jpg" class="js-avatar">
            
        </a>

        <hgroup>
          <h1 class="header-author"><a href="/" title="Hi Mate">muhe</a></h1>
        </hgroup>

        
        <p class="header-subtitle">control $pc, control the world</p>
        
        
        
            <div id="switch-btn" class="switch-btn">
                <div class="icon">
                    <div class="icon-ctn">
                        <div class="icon-wrap icon-house" data-idx="0">
                            <div class="birdhouse"></div>
                            <div class="birdhouse_holes"></div>
                        </div>
                        <div class="icon-wrap icon-ribbon hide" data-idx="1">
                            <div class="ribbon"></div>
                        </div>
                        
                        <div class="icon-wrap icon-link hide" data-idx="2">
                            <div class="loopback_l"></div>
                            <div class="loopback_r"></div>
                        </div>
                        
                        
                        <div class="icon-wrap icon-me hide" data-idx="3">
                            <div class="user"></div>
                            <div class="shoulder"></div>
                        </div>
                        
                    </div>
                    
                </div>
                <div class="tips-box hide">
                    <div class="tips-arrow"></div>
                    <ul class="tips-inner">
                        <li>菜单</li>
                        <li>标签</li>
                        
                        <li>友情链接</li>
                        
                        
                        <li>关于我</li>
                        
                    </ul>
                </div>
            </div>
        

        <div id="switch-area" class="switch-area">
            <div class="switch-wrap">
                <section class="switch-part switch-part1">
                    <nav class="header-menu">
                        <ul>
                        
                            <li><a href="/">博客首页</a></li>
                        
                            <li><a href="/archives">所有文章</a></li>
                        
                            <li><a href="/frinds">友情链接</a></li>
                        
                            <li><a href="/about">关于我</a></li>
                        
                            <li><a href="/Pwnable-Log">Pwnable</a></li>
                        
                        </ul>
                    </nav>
                    <nav class="header-nav">
                        <ul class="social">
                            
                                <a class="fl github" target="_blank" href="https://github.com/o0xmuhe" title="github">github</a>
                            
                                <a class="fl weibo" target="_blank" href="http://weibo.com/2070174943/" title="weibo">weibo</a>
                            
                                <a class="fl twitter" target="_blank" href="https://twitter.com/0xmuhe" title="twitter">twitter</a>
                            
                                <a class="fl rss" target="_blank" href="/atom.xml" title="rss">rss</a>
                            
                        </ul>
                    </nav>
                </section>
                
                
                <section class="switch-part switch-part2">
                    <div class="widget tagcloud" id="js-tagcloud">
                        <a href="/tags/1day/" style="font-size: 10px;">1day</a> <a href="/tags/Adobe/" style="font-size: 11.43px;">Adobe</a> <a href="/tags/Adobe-Acrobat-Reader/" style="font-size: 10px;">Adobe Acrobat Reader</a> <a href="/tags/Adobe-Reader/" style="font-size: 11.43px;">Adobe Reader</a> <a href="/tags/Antlr/" style="font-size: 10px;">Antlr</a> <a href="/tags/Apple/" style="font-size: 10px;">Apple</a> <a href="/tags/Bindiff/" style="font-size: 10px;">Bindiff</a> <a href="/tags/C/" style="font-size: 11.43px;">C</a> <a href="/tags/CTF/" style="font-size: 10px;">CTF</a> <a href="/tags/CTF-Writeup/" style="font-size: 10px;">CTF Writeup</a> <a href="/tags/CVE/" style="font-size: 10px;">CVE</a> <a href="/tags/Compilers/" style="font-size: 10px;">Compilers</a> <a href="/tags/ESXi/" style="font-size: 10px;">ESXi</a> <a href="/tags/Frida/" style="font-size: 10px;">Frida</a> <a href="/tags/IDA/" style="font-size: 12.86px;">IDA</a> <a href="/tags/IPC/" style="font-size: 11.43px;">IPC</a> <a href="/tags/LLVM/" style="font-size: 10px;">LLVM</a> <a href="/tags/Linux/" style="font-size: 12.86px;">Linux</a> <a href="/tags/MacOS/" style="font-size: 11.43px;">MacOS</a> <a href="/tags/Mach/" style="font-size: 10px;">Mach</a> <a href="/tags/PANDA/" style="font-size: 10px;">PANDA</a> <a href="/tags/PoC/" style="font-size: 11.43px;">PoC</a> <a href="/tags/Python/" style="font-size: 10px;">Python</a> <a href="/tags/RE/" style="font-size: 10px;">RE</a> <a href="/tags/Snell/" style="font-size: 10px;">Snell</a> <a href="/tags/Study/" style="font-size: 15.71px;">Study</a> <a href="/tags/Surge/" style="font-size: 10px;">Surge</a> <a href="/tags/Symbolic-Execution/" style="font-size: 10px;">Symbolic Execution</a> <a href="/tags/Tools/" style="font-size: 11.43px;">Tools</a> <a href="/tags/UaF/" style="font-size: 10px;">UaF</a> <a href="/tags/Webkit/" style="font-size: 10px;">Webkit</a> <a href="/tags/android/" style="font-size: 10px;">android</a> <a href="/tags/angr/" style="font-size: 11.43px;">angr</a> <a href="/tags/compiler/" style="font-size: 10px;">compiler</a> <a href="/tags/ctf/" style="font-size: 18.57px;">ctf</a> <a href="/tags/ctf-writeup/" style="font-size: 20px;">ctf writeup</a> <a href="/tags/debug/" style="font-size: 10px;">debug</a> <a href="/tags/env-config/" style="font-size: 10px;">env config</a> <a href="/tags/exploit/" style="font-size: 15.71px;">exploit</a> <a href="/tags/frida/" style="font-size: 10px;">frida</a> <a href="/tags/fuzz/" style="font-size: 14.29px;">fuzz</a> <a href="/tags/gdb/" style="font-size: 10px;">gdb</a> <a href="/tags/glibc%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/" style="font-size: 10px;">glibc内存管理</a> <a href="/tags/life/" style="font-size: 11.43px;">life</a> <a href="/tags/linux/" style="font-size: 10px;">linux</a> <a href="/tags/linux-kernel/" style="font-size: 12.86px;">linux kernel</a> <a href="/tags/macOS/" style="font-size: 17.14px;">macOS</a> <a href="/tags/mips/" style="font-size: 10px;">mips</a> <a href="/tags/paper/" style="font-size: 10px;">paper</a> <a href="/tags/peach/" style="font-size: 10px;">peach</a> <a href="/tags/pwn/" style="font-size: 15.71px;">pwn</a> <a href="/tags/python/" style="font-size: 10px;">python</a> <a href="/tags/ret-2-dl-resolve/" style="font-size: 10px;">ret 2 dl-resolve</a> <a href="/tags/study/" style="font-size: 12.86px;">study</a> <a href="/tags/tools/" style="font-size: 10px;">tools</a> <a href="/tags/uaf/" style="font-size: 10px;">uaf</a> <a href="/tags/unicorn-engine/" style="font-size: 10px;">unicorn engine</a> <a href="/tags/vuln-analysis/" style="font-size: 10px;">vuln analysis</a> <a href="/tags/wargame/" style="font-size: 11.43px;">wargame</a> <a href="/tags/webkit/" style="font-size: 12.86px;">webkit</a> <a href="/tags/winafl/" style="font-size: 10px;">winafl</a> <a href="/tags/windows-kernel/" style="font-size: 12.86px;">windows kernel</a> <a href="/tags/writeup/" style="font-size: 10px;">writeup</a> <a href="/tags/%E5%85%B6%E4%BB%96/" style="font-size: 10px;">其他</a> <a href="/tags/%E5%B7%A5%E5%85%B7/" style="font-size: 10px;">工具</a> <a href="/tags/%E6%84%9F%E6%82%9F/" style="font-size: 10px;">感悟</a> <a href="/tags/%E6%84%9F%E6%83%B3/" style="font-size: 10px;">感想</a> <a href="/tags/%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/" style="font-size: 15.71px;">漏洞分析</a> <a href="/tags/%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/" style="font-size: 11.43px;">环境配置</a> <a href="/tags/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86/" style="font-size: 11.43px;">编译原理</a>
                    </div>
                </section>
                
                
                
                <section class="switch-part switch-part3">
                    <div id="js-friends">
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://syclover.sinaapp.com/">Syclover Team</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="https://weibo.com/u/5376172367">最爱的高老师</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.Ox9A82.com">0x9A82学弟</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://k1n9.me/">K1n9师傅</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.cnblogs.com/iamstudy">L3mon</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.xianyusec.com">咸鱼</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://rootclay.com">rootclay</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://v1ct0r.com/">V1ct0r</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://godot.win">Godot学弟</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://hebic.me/">Homaebic学弟</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="https://iqwq.me">两米的sco4x0</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="https://zmy.im/">JimmyZhou</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://silic.top/">灭亡叔叔</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="https://dwx.io">Jason</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="	http://www.0aa.me/">Mosuan</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://whereisk0shl.top">k0sh1</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://winter3un.github.io">WinterSun</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://venenof.com">Venenof</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://r0p.me/">Icemakr</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://bestwing.me/">Swing</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="https://www.hackfun.org/">4ido10n</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.hackersb.cn/">王松_Striker</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.cnblogs.com/7top/">7top</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.bendawang.site">bendawang</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://yixuankeer.win">前端joker大佬</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://blog.lc4t.me">lc4t</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://www.inksec.cn/">Szrzvdny</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://sixwha1e.github.io/">漂亮的sixwhale小姐姐</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://ctfrank.org">CTF Rank</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="http://askook.me/">A酱</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="/idoge.cc">重庆五套房的小葱</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="/stone.moe">石头</a>
                    
                      <a target="_blank" class="main-nav-link switch-friends-link" href="/pi4net.com">邢老师最优秀</a>
                    
                    </div>
                </section>
                

                
                
                <section class="switch-part switch-part4">
                
                    <div id="js-aboutme">二进制安全. Member of Syclover. CTFer/INTJ.</div>
                </section>
                
            </div>
        </div>
    </header>                
</div>
    </div>
    <div class="mid-col">
      <nav id="mobile-nav">
      <div class="overlay">
          <div class="slider-trigger"></div>
          <h1 class="header-author js-mobile-header hide"><a href="/" title="Me">muhe</a></h1>
      </div>
    <div class="intrude-less">
        <header id="header" class="inner">
            <a href="/" class="profilepic">
                
                    <img lazy-src="/img/head.jpg" class="js-avatar">
                
            </a>
            <hgroup>
              <h1 class="header-author"><a href="/" title="Me">muhe</a></h1>
            </hgroup>
            
            <p class="header-subtitle">control $pc, control the world</p>
            
            <nav class="header-menu">
                <ul>
                
                    <li><a href="/">博客首页</a></li>
                
                    <li><a href="/archives">所有文章</a></li>
                
                    <li><a href="/frinds">友情链接</a></li>
                
                    <li><a href="/about">关于我</a></li>
                
                    <li><a href="/Pwnable-Log">Pwnable</a></li>
                
                <div class="clearfix"></div>
                </ul>
            </nav>
            <nav class="header-nav">
                <div class="social">
                    
                        <a class="github" target="_blank" href="https://github.com/o0xmuhe" title="github">github</a>
                    
                        <a class="weibo" target="_blank" href="http://weibo.com/2070174943/" title="weibo">weibo</a>
                    
                        <a class="twitter" target="_blank" href="https://twitter.com/0xmuhe" title="twitter">twitter</a>
                    
                        <a class="rss" target="_blank" href="/atom.xml" title="rss">rss</a>
                    
                </div>
            </nav>
        </header>                
    </div>
</nav>
      <div class="body-wrap"><article id="post-Have-fun-with-glibc内存管理" class="article article-type-post" itemscope itemprop="blogPost">
  
    <div class="article-meta">
      <a href="/2016/11/21/Have-fun-with-glibc%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/" class="article-date">
      <time datetime="2016-11-21T12:38:22.000Z" itemprop="datePublished">2016-11-21</time>
</a>
    </div>
  
  <div class="article-inner">
    
      <input type="hidden" class="isFancy" />
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      Have fun with glibc内存管理
    </h1>
  

      </header>
      
      <div class="article-info article-info-post">
        

        
    <div class="article-tag tagcloud">
        <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/glibc%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/" rel="tag">glibc内存管理</a></li></ul>
    </div>

        <div class="clearfix"></div>
      </div>
      
    
    <div class="article-entry" itemprop="articleBody">
      
          
        <ul>
<li>使用的源码版本 glibc-2.24</li>
<li>持续更新，治疗拖延症。</li>
</ul>
<a id="more"></a>

<h4 id="1-malloc-分析"><a href="#1-malloc-分析" class="headerlink" title="1.malloc 分析"></a>1.malloc 分析</h4><p>​    malloc其实是调用了<code>void *__libc_malloc (size_t bytes)</code>，但是这个函数实质是对<code>static void *_int_malloc (mstate av, size_t bytes)</code>的封装。</p>
<p>​    分析开始，先来看<code>void *__libc_malloc (size_t bytes)</code>函数</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> *__libc_malloc (<span class="keyword">size_t</span> bytes)</span><br><span class="line">&#123;</span><br><span class="line">  mstate ar_ptr;</span><br><span class="line">  <span class="keyword">void</span> *victim;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">//首先检查是否存在内存分配的hook函数，如果有，就直接调用；hook函数主要</span></span><br><span class="line">  <span class="comment">//是进程创建新线程的时候内存分配，或者支持用户提供的内存分配函数。</span></span><br><span class="line">  <span class="keyword">void</span> *(*hook) (<span class="keyword">size_t</span>, <span class="keyword">const</span> <span class="keyword">void</span> *)</span><br><span class="line">    = atomic_forced_read (__malloc_hook);</span><br><span class="line">  <span class="keyword">if</span> (__builtin_expect (hook != <span class="literal">NULL</span>, <span class="number">0</span>))</span><br><span class="line">    <span class="keyword">return</span> (*hook)(bytes, RETURN_ADDRESS (<span class="number">0</span>));</span><br><span class="line"></span><br><span class="line">  arena_get (ar_ptr, bytes);</span><br><span class="line">  </span><br><span class="line">  victim = _int_malloc (ar_ptr, bytes);</span><br><span class="line">  <span class="comment">/* Retry with another arena only if we were able to find a usable arena</span></span><br><span class="line"><span class="comment">     before.  */</span></span><br><span class="line">  <span class="keyword">if</span> (!victim &amp;&amp; ar_ptr != <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">      LIBC_PROBE (memory_malloc_retry, <span class="number">1</span>, bytes);</span><br><span class="line">      ar_ptr = arena_get_retry (ar_ptr, bytes);</span><br><span class="line">      victim = _int_malloc (ar_ptr, bytes);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">//若分配成功，释放锁</span></span><br><span class="line">  <span class="keyword">if</span> (ar_ptr != <span class="literal">NULL</span>)</span><br><span class="line">    (<span class="keyword">void</span>) mutex_unlock (&amp;ar_ptr-&gt;mutex);</span><br><span class="line"></span><br><span class="line">  assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||</span><br><span class="line">          ar_ptr == arena_for_chunk (mem2chunk (victim)));</span><br><span class="line">  <span class="keyword">return</span> victim;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>arena_get (ar_ptr, bytes)</code>展开宏就是</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> arena_get(ptr, size) do &#123; \</span></span><br><span class="line">      ptr = thread_arena;						      \</span><br><span class="line">      arena_lock (ptr, <span class="built_in">size</span>);						      \</span><br><span class="line">  &#125; <span class="keyword">while</span> (<span class="number">0</span>)</span><br></pre></td></tr></table></figure>

<p>​    获得分配区并加锁，之后就进入了主要负责内存分配的<code>_int_malloc (ar_ptr, bytes)</code>函数</p>
<p>​    该函数代码特别长，只能一部分一部分看了，首先给出原型，函数有两个参数，即分配区和要分配的内存的大小(用户传进来的，并不是真正的要分配的大小)。</p>
<h6 id="1-概述"><a href="#1-概述" class="headerlink" title="1.概述"></a>1.概述</h6><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> *</span><br><span class="line">_int_malloc (mstate av, <span class="keyword">size_t</span> bytes) <span class="comment">//分配区，大小</span></span><br><span class="line">&#123;</span><br><span class="line">  INTERNAL_SIZE_T nb;               <span class="comment">/* normalized request size */</span></span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">int</span> idx;                 <span class="comment">/* associated bin index */</span></span><br><span class="line">  mbinptr bin;                      <span class="comment">/* associated bin */</span></span><br><span class="line"></span><br><span class="line">  mchunkptr victim;                 <span class="comment">/* inspected/selected chunk */</span></span><br><span class="line">  INTERNAL_SIZE_T <span class="built_in">size</span>;             <span class="comment">/* its size */</span></span><br><span class="line">  <span class="keyword">int</span> victim_index;                 <span class="comment">/* its bin index */</span></span><br><span class="line"></span><br><span class="line">  mchunkptr remainder;              <span class="comment">/* remainder from a split */</span></span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">long</span> remainder_size;     <span class="comment">/* its size */</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">int</span> block;               <span class="comment">/* bit map traverser */</span></span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="built_in">bit</span>;                 <span class="comment">/* bit map traverser */</span></span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="built_in">map</span>;                 <span class="comment">/* current word of binmap */</span></span><br><span class="line"></span><br><span class="line">  mchunkptr fwd;                    <span class="comment">/* misc temp for linking */</span></span><br><span class="line">  mchunkptr bck;                    <span class="comment">/* misc temp for linking */</span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">char</span> *errstr = <span class="literal">NULL</span>;</span><br><span class="line">  <span class="comment">/*</span></span><br><span class="line"><span class="comment">     Convert request size to internal form by adding SIZE_SZ bytes</span></span><br><span class="line"><span class="comment">     overhead plus possibly more to obtain necessary alignment and/or</span></span><br><span class="line"><span class="comment">     to obtain a size of at least MINSIZE, the smallest allocatable</span></span><br><span class="line"><span class="comment">     size. Also, checked_request2size traps (returning 0) request sizes</span></span><br><span class="line"><span class="comment">     that are so large that they wrap around zero when padded and</span></span><br><span class="line"><span class="comment">     aligned.</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  checked_request2size (bytes, nb);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* There are no usable arenas.  Fall back to sysmalloc to get a chunk from</span></span><br><span class="line"><span class="comment">     mmap.  */</span></span><br><span class="line">  <span class="keyword">if</span> (__glibc_unlikely (av == <span class="literal">NULL</span>))</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">void</span> *p = sysmalloc (nb, av);</span><br><span class="line">      <span class="keyword">if</span> (p != <span class="literal">NULL</span>)</span><br><span class="line">4alloc_perturb (p, bytes);</span><br><span class="line">      <span class="keyword">return</span> p;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>这个转换是把需要的内存大小bytes，转换成需要分配的chunk的大小nb。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> checked_request2size(req, sz)                             \</span></span><br><span class="line">  <span class="keyword">if</span> (REQUEST_OUT_OF_RANGE (req)) &#123;					      \</span><br><span class="line">      __set_errno (ENOMEM);						      \</span><br><span class="line">      <span class="keyword">return</span> <span class="number">0</span>;								      \</span><br><span class="line">    &#125;									      \</span><br><span class="line">  (sz) = request2size (req);</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> request2size(req)                                         \</span></span><br><span class="line">  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK &lt; MINSIZE)  ?             \</span><br><span class="line">   MINSIZE :                                                      \</span><br><span class="line">   ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) &amp; ~MALLOC_ALIGN_MASK)</span><br></pre></td></tr></table></figure>

<hr>
<h6 id="2-fastbin"><a href="#2-fastbin" class="headerlink" title="2.fastbin"></a>2.fastbin</h6><p>如果分配大小正好是fastbin，那就直接从fastbin分配。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line">  <span class="comment">/*</span></span><br><span class="line"><span class="comment">     If the size qualifies as a fastbin, first check corresponding bin.</span></span><br><span class="line"><span class="comment">     This code is safe to execute even if av is not yet initialized, so we</span></span><br><span class="line"><span class="comment">     can try it without checking, which saves some time on this fast path.</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">4</span><br><span class="line">  <span class="comment">//要分配的值小于等于最大的fastbin大小</span></span><br><span class="line">  <span class="keyword">if</span> ((<span class="keyword">unsigned</span> <span class="keyword">long</span>) (nb) &lt;= (<span class="keyword">unsigned</span> <span class="keyword">long</span>) (get_max_fast ()))</span><br><span class="line">    &#123;</span><br><span class="line">      idx = fastbin_index (nb);</span><br><span class="line">      mfastbinptr *fb = &amp;fastbin (av, idx);</span><br><span class="line">      mchunkptr pp = *fb;</span><br><span class="line">      <span class="keyword">do</span></span><br><span class="line">        &#123;</span><br><span class="line">          victim = pp;</span><br><span class="line">          <span class="keyword">if</span> (victim == <span class="literal">NULL</span>)</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">      <span class="keyword">while</span> ((pp = catomic_compare_and_exchange_val_acq (fb, victim-&gt;fd, victim))</span><br><span class="line">             != victim);</span><br><span class="line">      <span class="keyword">if</span> (victim != <span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="keyword">if</span> (__builtin_expect (fastbin_index (chunksize (victim)) != idx, <span class="number">0</span>))</span><br><span class="line">            &#123;</span><br><span class="line">              errstr = <span class="string">"malloc(): memory corruption (fast)"</span>;</span><br><span class="line">            errout:</span><br><span class="line">              malloc_printerr (check_action, errstr, chunk2mem (victim), av);</span><br><span class="line">              <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">            &#125;</span><br><span class="line">          check_remalloced_chunk (av, victim, nb);</span><br><span class="line">          <span class="keyword">void</span> *p = chunk2mem (victim);</span><br><span class="line">          alloc_perturb (p, bytes);</span><br><span class="line">          <span class="keyword">return</span> p;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//一些其他的宏</span></span><br><span class="line"><span class="comment">/* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.</span></span><br><span class="line"><span class="comment">   Return the old *MEM value.  */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> !defined atomic_compare_and_exchange_val_acq \</span></span><br><span class="line">    &amp;&amp; defined __arch_compare_and_exchange_val_32_acq</span><br><span class="line"><span class="meta"># <span class="meta-keyword">define</span> atomic_compare_and_exchange_val_acq(mem, newval, oldval) \</span></span><br><span class="line">  __atomic_val_bysize (__arch_compare_and_exchange_val,acq,		      \</span><br><span class="line">44       mem, newval, oldval)</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> catomic_compare_and_exchange_val_acq</span></span><br><span class="line"><span class="meta"># <span class="meta-keyword">ifdef</span> __arch_c_compare_and_exchange_val_32_acq</span></span><br><span class="line"><span class="meta">#  <span class="meta-keyword">define</span> catomic_compare_and_exchange_val_acq(mem, newval, oldval) \</span></span><br><span class="line">  __atomic_val_bysize (__arch_c_compare_and_exchange_val,acq,		      \</span><br><span class="line">44       mem, newval, oldval)</span><br><span class="line"><span class="meta"># <span class="meta-keyword">else</span></span></span><br><span class="line"><span class="meta">#  <span class="meta-keyword">define</span> catomic_compare_and_exchange_val_acq(mem, newval, oldval) \</span></span><br><span class="line">  atomic_compare_and_exchange_val_acq (mem, newval, oldval)</span><br><span class="line"><span class="meta"># <span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//展开之后</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> __atomic_val_bysize(pre, post, mem, ...)			      \</span></span><br><span class="line">  (&#123;									      \</span><br><span class="line">    __typeof (*mem) __atg1_result;					      \</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">sizeof</span> (*mem) == <span class="number">1</span>)						      \</span><br><span class="line">      __atg1_result = pre##_8_##post (mem, __VA_ARGS__);		      \</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">sizeof</span> (*mem) == <span class="number">2</span>)					      \</span><br><span class="line">      __atg1_result = pre##_16_##post (mem, __VA_ARGS__);		      \</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">sizeof</span> (*mem) == <span class="number">4</span>)					      \</span><br><span class="line">      __atg1_result = pre##_32_##post (mem, __VA_ARGS__);		      \</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">sizeof</span> (*mem) == <span class="number">8</span>)					      \</span><br><span class="line">      __atg1_result = pre##_64_##post (mem, __VA_ARGS__);		      \</span><br><span class="line">    <span class="keyword">else</span>								      \</span><br><span class="line">      <span class="built_in">abort</span> ();								      \</span><br><span class="line">    __atg1_result;							      \</span><br><span class="line">  &#125;)</span><br></pre></td></tr></table></figure>

<p>​    首先根据分配大小，获取该chunk所属的fastbin的index，然后根据index获取所需要的fastbin的空闲链表的头指针；然后将头指针的下一个chunk 作为空闲chunk 链表的头部。后面check之后，直接使用<code>chunk2mem()</code>把用户所需的内存块转换并且返回。</p>
<hr>
<h6 id="3-small-bin"><a href="#3-small-bin" class="headerlink" title="3.small bin"></a>3.small bin</h6><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment">    If a small request, check regular bin.  Since these "smallbins"</span></span><br><span class="line"><span class="comment">    hold one size each, no searching within bins is necessary.</span></span><br><span class="line"><span class="comment">    (For a large request, we need to wait until unsorted chunks are</span></span><br><span class="line"><span class="comment">    processed to find best fit. But for small ones, fits are exact</span></span><br><span class="line"><span class="comment">    anyway, so we can check now, which is faster.)</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (in_smallbin_range (nb))</span><br><span class="line">   &#123;</span><br><span class="line">     idx = smallbin_index (nb);</span><br><span class="line">     bin = bin_at (av, idx);</span><br><span class="line"></span><br><span class="line">     <span class="keyword">if</span> ((victim = last (bin)) != bin)<span class="comment">//与表头相同，说明链表是空的；不相同的话进入下面的逻辑</span></span><br><span class="line">       &#123;</span><br><span class="line">         <span class="keyword">if</span> (victim == <span class="number">0</span>) <span class="comment">/* initialization check */</span></span><br><span class="line">           malloc_consolidate (av); <span class="comment">//合并fastbin</span></span><br><span class="line">         <span class="keyword">else</span></span><br><span class="line">           &#123; </span><br><span class="line">           	<span class="comment">//将victim从双向循环链表中取出来</span></span><br><span class="line">             bck = victim-&gt;bk;</span><br><span class="line"><span class="keyword">if</span> (__glibc_unlikely (bck-&gt;fd != victim)) </span><br><span class="line">               &#123;</span><br><span class="line">                 errstr = <span class="string">"malloc(): smallbin double linked list corrupted"</span>;</span><br><span class="line">                 <span class="keyword">goto</span> errout;</span><br><span class="line">               &#125;</span><br><span class="line">44<span class="comment">//设置inuse标志。</span></span><br><span class="line">             set_inuse_bit_at_offset (victim, nb);</span><br><span class="line">             bin-&gt;bk = bck;</span><br><span class="line">             bck-&gt;fd = bin;</span><br><span class="line"></span><br><span class="line">             <span class="keyword">if</span> (av != &amp;main_arena)</span><br><span class="line">               victim-&gt;<span class="built_in">size</span> |= NON_MAIN_ARENA;</span><br><span class="line">             check_malloced_chunk (av, victim, nb);</span><br><span class="line">             <span class="keyword">void</span> *p = chunk2mem (victim);</span><br><span class="line">             alloc_perturb (p, bytes);</span><br><span class="line">             <span class="keyword">return</span> p;</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>

<p>​    首先还是根据分配的大小，找到所对应的small bin的index，然后根据这个index去找到所需的small bin的空闲链表头指针；然后将最后一个chunk赋值给victim，然后做判断，如果和表头相同，那么说明这个链表当前是空的，就不能从这个small bin中分配内存，这就要走后面的流程了；如果不同，这里有两种情况：</p>
<ol>
<li>victim为0，即还没有初始化双向循环链表，这时候就要去合并fast bin；</li>
<li>victim不为0，直接把victim从small bin中取出来，设置标志位，然后判断是否属于主分配区，之后调用<code>chunk2meme()</code>转换成用户所需内存空间并返回。</li>
</ol>
<hr>
<h6 id="4-large-bin"><a href="#4-large-bin" class="headerlink" title="4.large bin"></a>4.large bin</h6><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">   If this is a large request, consolidate fastbins before continuing.</span></span><br><span class="line"><span class="comment">   While it might look excessive to kill all fastbins before</span></span><br><span class="line"><span class="comment">   even seeing if there is space available, this avoids</span></span><br><span class="line"><span class="comment">   fragmentation problems normally associated with fastbins.</span></span><br><span class="line"><span class="comment">   Also, in practice, programs tend to have runs of either small or</span></span><br><span class="line"><span class="comment">   large requests, but less often mixtures, so consolidation is not</span></span><br><span class="line"><span class="comment">   invoked all that often in most programs. And the programs that</span></span><br><span class="line"><span class="comment">   it is called frequently in otherwise tend to fragment.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">  &#123;</span><br><span class="line">    idx = largebin_index (nb);</span><br><span class="line">    <span class="keyword">if</span> (have_fastchunks (av))</span><br><span class="line"> 	<span class="comment">//合并fastbin中的chunk，加入unsorted bin</span></span><br><span class="line">      malloc_consolidate (av);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<p>​    在分配之前会先合并fast bin中的chunk，加入unsorted bin。</p>
<p>​    下面代码是遍历unsorted bin中的空闲块，加入到相应的small bin 或者large bin之中，代码比较长，所以一部分一部分的看。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">   Process recently freed or remaindered chunks, taking one only if</span></span><br><span class="line"><span class="comment">   it is exact fit, or, if this a small request, the chunk is remainder from</span></span><br><span class="line"><span class="comment">   the most recent non-exact fit.  Place other traversed chunks in</span></span><br><span class="line"><span class="comment">   bins.  Note that this step is the only place in any routine where</span></span><br><span class="line"><span class="comment">   chunks are placed in bins.</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">   The outer loop here is needed because we might not realize until</span></span><br><span class="line"><span class="comment">   near the end of malloc that we should have consolidated, so must</span></span><br><span class="line"><span class="comment">   do so and retry. This happens at most once, and only when we would</span></span><br><span class="line"><span class="comment">   otherwise need to expand memory to service a "small" request.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (;; )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">int</span> iters = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> ((victim = unsorted_chunks (av)-&gt;bk) != unsorted_chunks (av))</span><br><span class="line">      &#123;</span><br><span class="line">        bck = victim-&gt;bk;</span><br><span class="line">        <span class="keyword">if</span> (__builtin_expect (victim-&gt;<span class="built_in">size</span> &lt;= <span class="number">2</span> * SIZE_SZ, <span class="number">0</span>)</span><br><span class="line">            || __builtin_expect (victim-&gt;<span class="built_in">size</span> &gt; av-&gt;system_mem, <span class="number">0</span>))</span><br><span class="line">          malloc_printerr (check_action, <span class="string">"malloc(): memory corruption"</span>,</span><br><span class="line">                           chunk2mem (victim), av);</span><br><span class="line">        <span class="built_in">size</span> = chunksize (victim);</span><br></pre></td></tr></table></figure>

<p>这里先是反向遍历链表，检查size，要小于等于 <code>2*SIZE_SZ</code>，并且不能大于系统分配的总量。然后获取chunk的size。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">          If a small request, try to use last remainder if it is the</span></span><br><span class="line"><span class="comment">          only chunk in unsorted bin.  This helps promote locality for</span></span><br><span class="line"><span class="comment">          runs of consecutive small requests. This is the only</span></span><br><span class="line"><span class="comment">          exception to best-fit, and applies only when there is</span></span><br><span class="line"><span class="comment">          no exact fit for a small chunk.</span></span><br><span class="line"><span class="comment">        */</span></span><br><span class="line"></span><br><span class="line">       <span class="keyword">if</span> (in_smallbin_range (nb) &amp;&amp;</span><br><span class="line">           bck == unsorted_chunks (av) &amp;&amp;</span><br><span class="line">           victim == av-&gt;last_remainder &amp;&amp;</span><br><span class="line">           (<span class="keyword">unsigned</span> <span class="keyword">long</span>) (<span class="built_in">size</span>) &gt; (<span class="keyword">unsigned</span> <span class="keyword">long</span>) (nb + MINSIZE))</span><br><span class="line">         &#123;</span><br><span class="line">           <span class="comment">/* split and reattach remainder */</span></span><br><span class="line">           remainder_size = <span class="built_in">size</span> - nb;</span><br><span class="line">           remainder = chunk_at_offset (victim, nb);</span><br><span class="line">           unsorted_chunks (av)-&gt;bk = unsorted_chunks (av)-&gt;fd = remainder;</span><br><span class="line">           av-&gt;last_remainder = remainder;</span><br><span class="line">           remainder-&gt;bk = remainder-&gt;fd = unsorted_chunks (av);</span><br><span class="line">  <span class="comment">//large chunk</span></span><br><span class="line">           <span class="keyword">if</span> (!in_smallbin_range (remainder_size))</span><br><span class="line">             &#123;</span><br><span class="line">               remainder-&gt;fd_nextsize = <span class="literal">NULL</span>;</span><br><span class="line">               remainder-&gt;bk_nextsize = <span class="literal">NULL</span>;</span><br><span class="line">             &#125;</span><br><span class="line"></span><br><span class="line">           set_head (victim, nb | PREV_INUSE |</span><br><span class="line">                     (av != &amp;main_arena ? NON_MAIN_ARENA : <span class="number">0</span>));</span><br><span class="line">           set_head (remainder, remainder_size | PREV_INUSE);</span><br><span class="line">           set_foot (remainder, remainder_size);</span><br><span class="line"></span><br><span class="line">           check_malloced_chunk (av, victim, nb);</span><br><span class="line">           <span class="keyword">void</span> *p = chunk2mem (victim);</span><br><span class="line">           alloc_perturb (p, bytes);</span><br><span class="line">           <span class="keyword">return</span> p;</span><br><span class="line">         &#125;</span><br></pre></td></tr></table></figure>

<p>​    之前的small bin 没有成功分配，并且只有一个chunk的时候，那个chunk就是last remainder chunk，且last remainder chunk 的size大于所需要的<code>大小+MINSIZE</code>，这个时候就可已从这个块中去分配所需要的内存。</p>
<p>​    后面就是从这个chunk 中切分出所需大小的chunk，计算切分后剩下chunk 的大小，将剩下的chunk加入unsorted bin 的链表中，并将剩下的chunk 作为分配区的last remainder chunk，若剩下的chunk 属于large bin chunk，将该chunk 的<code>fd_nextsize</code> 和<code>bk_nextsize</code>设置为NULL。</p>
<p>​    然后设置一些标志位，对于last remainder chunk需要调用<code>set_foot()</code>，因为处于空闲状态的chunk的<code>pre_size</code>才是有效的；之后就是利用<code>chunk2mem()</code>转换，然后返回给用户了。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* remove from unsorted list */</span></span><br><span class="line">unsorted_chunks (av)-&gt;bk = bck;</span><br><span class="line">bck-&gt;fd = unsorted_chunks (av);</span><br></pre></td></tr></table></figure>

<p>​    将双向循环链表中的最后一个chunk 移除</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">/* Take now instead of binning if exact fit */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="built_in">size</span> == nb)</span><br><span class="line">  &#123;</span><br><span class="line">    set_inuse_bit_at_offset (victim, <span class="built_in">size</span>);</span><br><span class="line">    <span class="keyword">if</span> (av != &amp;main_arena)</span><br><span class="line">      victim-&gt;<span class="built_in">size</span> |= NON_MAIN_ARENA;</span><br><span class="line">    check_malloced_chunk (av, victim, nb);</span><br><span class="line">    <span class="keyword">void</span> *p = chunk2mem (victim);</span><br><span class="line">    alloc_perturb (p, bytes);</span><br><span class="line">    <span class="keyword">return</span> p;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<p>​    如果当前遍历的chunk的size正好和需要的分配的大小nb相等，那直接就返回当前块：设置inuse标志位，然后判断是否属于主分配区，并设置相应的标志位，之后调用<code>chunk2mem()</code>转换后就返回给用户了。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* place chunk in bin */</span></span><br><span class="line"></span><br><span class="line">         <span class="keyword">if</span> (in_smallbin_range (<span class="built_in">size</span>))</span><br><span class="line">           &#123;</span><br><span class="line">             victim_index = smallbin_index (<span class="built_in">size</span>);</span><br><span class="line">             bck = bin_at (av, victim_index);</span><br><span class="line">             fwd = bck-&gt;fd;</span><br><span class="line">           &#125;</span><br></pre></td></tr></table></figure>

<p>判断当前遍历的chunk是否在small bin的范围，在的话插入到small bin的表头，成为第一个块。</p>
<p>不在small bin的范围的话，就是large bin了，就走下面的逻辑：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"> </span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">  &#123;</span><br><span class="line">    victim_index = largebin_index (<span class="built_in">size</span>);</span><br><span class="line">    bck = bin_at (av, victim_index);</span><br><span class="line">    fwd = bck-&gt;fd;</span><br></pre></td></tr></table></figure>

<p>类似上面的，把当前遍历的这个chunk插入到large bin的表头成为large bin的第一个块。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* maintain large bins in sorted order */</span></span><br><span class="line">           <span class="keyword">if</span> (fwd != bck)</span><br><span class="line">             &#123;</span><br><span class="line">               <span class="comment">/* Or with inuse bit to speed comparisons */</span></span><br><span class="line">               <span class="built_in">size</span> |= PREV_INUSE;</span><br><span class="line">               <span class="comment">/* if smaller than smallest, bypass loop below */</span></span><br><span class="line">               assert ((bck-&gt;bk-&gt;<span class="built_in">size</span> &amp; NON_MAIN_ARENA) == <span class="number">0</span>);</span><br><span class="line">               <span class="keyword">if</span> ((<span class="keyword">unsigned</span> <span class="keyword">long</span>) (<span class="built_in">size</span>) &lt; (<span class="keyword">unsigned</span> <span class="keyword">long</span>) (bck-&gt;bk-&gt;<span class="built_in">size</span>))</span><br><span class="line">                 &#123;</span><br><span class="line">                   fwd = bck;</span><br><span class="line">                   bck = bck-&gt;bk;</span><br><span class="line"></span><br><span class="line">                   victim-&gt;fd_nextsize = fwd-&gt;fd;</span><br><span class="line">                   victim-&gt;bk_nextsize = fwd-&gt;fd-&gt;bk_nextsize;</span><br><span class="line">                   fwd-&gt;fd-&gt;bk_nextsize = victim-&gt;bk_nextsize-&gt;fd_nextsize = victim;</span><br><span class="line">                 &#125;</span><br></pre></td></tr></table></figure>

<p><code>if (fwd != bck)</code>意味着当前链表不为空，需要把当前的块插入large bin的链表中，设置inuse标志，并且插入到适合的位置。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">else</span></span><br><span class="line">                &#123;</span><br><span class="line">                  assert ((fwd-&gt;<span class="built_in">size</span> &amp; NON_MAIN_ARENA) == <span class="number">0</span>);</span><br><span class="line">                  <span class="keyword">while</span> ((<span class="keyword">unsigned</span> <span class="keyword">long</span>) <span class="built_in">size</span> &lt; fwd-&gt;<span class="built_in">size</span>)</span><br><span class="line">                    &#123;</span><br><span class="line">                      fwd = fwd-&gt;fd_nextsize;</span><br><span class="line">                      assert ((fwd-&gt;<span class="built_in">size</span> &amp; NON_MAIN_ARENA) == <span class="number">0</span>);</span><br><span class="line">                    &#125;</span><br></pre></td></tr></table></figure>

<p>如果size比最后一个chunk的siz还要小，那就直接插入到最后。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> ((<span class="keyword">unsigned</span> <span class="keyword">long</span>) <span class="built_in">size</span> == (<span class="keyword">unsigned</span> <span class="keyword">long</span>) fwd-&gt;<span class="built_in">size</span>)</span><br><span class="line">                   <span class="comment">/* Always insert in the second position.  */</span></span><br><span class="line">                   fwd = fwd-&gt;fd;</span><br><span class="line">                 <span class="keyword">else</span></span><br><span class="line">                   &#123;</span><br><span class="line">                     victim-&gt;fd_nextsize = fwd;</span><br><span class="line">                     victim-&gt;bk_nextsize = fwd-&gt;bk_nextsize;</span><br><span class="line">                     fwd-&gt;bk_nextsize = victim;</span><br><span class="line">                     victim-&gt;bk_nextsize-&gt;fd_nextsize = victim;</span><br><span class="line">                   &#125;</span><br><span class="line">                 bck = fwd-&gt;bk;</span><br></pre></td></tr></table></figure>

<p>正向遍历chunk size链表，找到一个和当前chunk大小相同的chunk就退出，那么chunk size 链表中一定包含fwd 所指向的chunk，为了不修改chunk size 链表，当前chunk 只能插入fwd 之后。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    victim-&gt;fd_nextsize = victim-&gt;bk_nextsize = victim;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果large bin链表里没有chunk，那么就直接插入chunk size链表。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">mark_bin (av, victim_index);</span><br><span class="line">       victim-&gt;bk = bck;</span><br><span class="line">       victim-&gt;fd = fwd;</span><br><span class="line">       fwd-&gt;bk = victim;</span><br><span class="line">       bck-&gt;fd = victim;</span><br></pre></td></tr></table></figure>

<p>完成chunk的插入空闲链表之后，设置bitmap。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MAX_ITERS       10000</span></span><br><span class="line">          <span class="keyword">if</span> (++iters &gt;= MAX_ITERS)</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br></pre></td></tr></table></figure>

<p>这里设置了最大的迭代次数，超出就直接退出了。</p>
<p>​    当将unsorted bin 中的空闲chunk 加入到相应的small bins 和large bins 后，将使用最佳匹配法分配large bin chunk。源代码如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">   If a large request, scan through the chunks of current bin in</span></span><br><span class="line"><span class="comment">   sorted order to find smallest that fits.  Use the skip list for this.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!in_smallbin_range (nb))</span><br><span class="line">  &#123;</span><br><span class="line">    bin = bin_at (av, idx);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* skip scan if empty or largest chunk is too small */</span></span><br><span class="line">    <span class="keyword">if</span> ((victim = first (bin)) != bin &amp;&amp;</span><br><span class="line">        (<span class="keyword">unsigned</span> <span class="keyword">long</span>) (victim-&gt;<span class="built_in">size</span>) &gt;= (<span class="keyword">unsigned</span> <span class="keyword">long</span>) (nb))</span><br><span class="line">      &#123;</span><br><span class="line">        victim = victim-&gt;bk_nextsize;</span><br><span class="line">        <span class="keyword">while</span> (((<span class="keyword">unsigned</span> <span class="keyword">long</span>) (<span class="built_in">size</span> = chunksize (victim)) &lt;</span><br><span class="line">                (<span class="keyword">unsigned</span> <span class="keyword">long</span>) (nb)))</span><br><span class="line">          victim = victim-&gt;bk_nextsize;</span><br></pre></td></tr></table></figure>

<p>​    如果所分配的块是large bin chunk，那么进入这段逻辑，当large bin list不为空且最大的chunk可以满足需要，就反向遍历链表，找到大小最合适的chunk，然后退出循环。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Avoid removing the first entry for a size so that the skip</span></span><br><span class="line"><span class="comment">              list does not have to be rerouted.  */</span></span><br><span class="line">           <span class="keyword">if</span> (victim != last (bin) &amp;&amp; victim-&gt;<span class="built_in">size</span> == victim-&gt;fd-&gt;<span class="built_in">size</span>)</span><br><span class="line">             victim = victim-&gt;fd;</span><br><span class="line"></span><br><span class="line">           remainder_size = <span class="built_in">size</span> - nb;</span><br><span class="line">           unlink (av, victim, bck, fwd);</span><br></pre></td></tr></table></figure>

<p>​    如果所选的chunk(即victim)不是最后一个chunk，且下一个块chunk大小和所选的chunk大小一致，那么把后面的那个chunk作为备选。</p>
<p>​    计算victim分割后剩余的size，然后使用<code>unlink()</code>宏去把victim从链表中取出来。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Exhaust */</span></span><br><span class="line">          <span class="keyword">if</span> (remainder_size &lt; MINSIZE)</span><br><span class="line">            &#123;</span><br><span class="line">              set_inuse_bit_at_offset (victim, <span class="built_in">size</span>);</span><br><span class="line">              <span class="keyword">if</span> (av != &amp;main_arena)</span><br><span class="line">                victim-&gt;<span class="built_in">size</span> |= NON_MAIN_ARENA;</span><br><span class="line">            &#125;</span><br></pre></td></tr></table></figure>

<p>​    之后判断分割后剩余大小，如果小于MINSIZE(分配的chunk要略大于需要的chunk)，那么就给victim设置inuse标志，然后根据是否是主分配区的判断，设置相应的标志位。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">           <span class="comment">/* Split */</span></span><br><span class="line">           <span class="keyword">else</span></span><br><span class="line">             &#123;</span><br><span class="line">               remainder = chunk_at_offset (victim, nb);</span><br><span class="line">               <span class="comment">/* We cannot assume the unsorted list is empty and therefore</span></span><br><span class="line"><span class="comment">                  have to perform a complete insert here.  */</span></span><br><span class="line">               bck = unsorted_chunks (av);</span><br><span class="line">               fwd = bck-&gt;fd;</span><br><span class="line"><span class="keyword">if</span> (__glibc_unlikely (fwd-&gt;bk != bck))</span><br><span class="line">                 &#123;</span><br><span class="line">                   errstr = <span class="string">"malloc(): corrupted unsorted chunks"</span>;</span><br><span class="line">                   <span class="keyword">goto</span> errout;</span><br><span class="line">                 &#125;</span><br><span class="line">               remainder-&gt;bk = bck;</span><br><span class="line">               remainder-&gt;fd = fwd;</span><br><span class="line">               bck-&gt;fd = remainder;</span><br><span class="line">               fwd-&gt;bk = remainder;</span><br><span class="line">               <span class="keyword">if</span> (!in_smallbin_range (remainder_size))</span><br><span class="line">                 &#123;</span><br><span class="line">                   remainder-&gt;fd_nextsize = <span class="literal">NULL</span>;</span><br><span class="line">                   remainder-&gt;bk_nextsize = <span class="literal">NULL</span>;</span><br><span class="line">                 &#125;</span><br><span class="line">               set_head (victim, nb | PREV_INUSE |</span><br><span class="line">                         (av != &amp;main_arena ? NON_MAIN_ARENA : <span class="number">0</span>));</span><br><span class="line">               set_head (remainder, remainder_size | PREV_INUSE);</span><br><span class="line">               set_foot (remainder, remainder_size);</span><br><span class="line">             &#125;</span><br><span class="line">           check_malloced_chunk (av, victim, nb);</span><br><span class="line">           <span class="keyword">void</span> *p = chunk2mem (victim);</span><br><span class="line">           alloc_perturb (p, bytes);</span><br><span class="line">           <span class="keyword">return</span> p;</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br></pre></td></tr></table></figure>

<p>​    从victim中分割出去的剩余部分作为新chunk加入到unsorted bin中，接着是判断大小，如果是large bin的范围，还要把<code>fd_nextsize</code>和<code>bk_nextsize</code>置为NULL，之后设置标志位，因为remainder空闲，所以还要设置foot(上面的分析里也有类似这段设置标志位的逻辑)。最后就很简单了，调用<code>chunk2mem()</code>的到可用的内存指针并返回给用户。</p>
<p>​    上面从最合适的small bin和large bin都没有合适的chunk去分配，那么就会查看比当前index大的下一个small bin 或者large bin中有没有合适的块去分配给用户，源码如下</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">        Search for a chunk by scanning bins, starting with next largest</span></span><br><span class="line"><span class="comment">        bin. This search is strictly by best-fit; i.e., the smallest</span></span><br><span class="line"><span class="comment">        (with ties going to approximately the least recently used) chunk</span></span><br><span class="line"><span class="comment">        that fits is selected.</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">        The bitmap avoids needing to check that most blocks are nonempty.</span></span><br><span class="line"><span class="comment">        The particular case of skipping all bins during warm-up phases</span></span><br><span class="line"><span class="comment">        when no chunks have been returned yet is faster than it might look.</span></span><br><span class="line"><span class="comment">      */</span></span><br><span class="line"></span><br><span class="line">     ++idx;</span><br><span class="line">     bin = bin_at (av, idx);</span><br><span class="line">     block = idx2block (idx);</span><br><span class="line">     <span class="built_in">map</span> = av-&gt;binmap[block];</span><br><span class="line">     <span class="built_in">bit</span> = idx2bit (idx);</span><br></pre></td></tr></table></figure>

<p>​    首先获取下一个bin，下面是<code>malloc_state</code>的结构体，bitmap是标识对应的bin中有没有空闲chunk。bitmap是按照block管理的，所以先获取了block，然后根据获取到的block去获取bitmap。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">malloc_state</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">  <span class="comment">/* Serialize access.  */</span></span><br><span class="line">  <span class="keyword">mutex_t</span> mutex;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Flags (formerly in max_fast).  */</span></span><br><span class="line">  <span class="keyword">int</span> flags;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Fastbins */</span></span><br><span class="line">  mfastbinptr fastbinsY[NFASTBINS];</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Base of the topmost chunk -- not otherwise kept in a bin */</span></span><br><span class="line">  mchunkptr top; <span class="comment">//point to the TOP CHUNK of malloc state -- by muhe</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* The remainder from the most recent split of a small request */</span></span><br><span class="line">  mchunkptr last_remainder;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Normal bins packed as described above */</span></span><br><span class="line">  mchunkptr bins[NBINS * <span class="number">2</span> - <span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Bitmap of bins */</span></span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">int</span> binmap[BINMAPSIZE];</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Linked list */</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">malloc_state</span> *<span class="title">next</span>;</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Linked list for free arenas.  Access to this field is serialized</span></span><br><span class="line"><span class="comment">     by free_list_lock in arena.c.  */</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">malloc_state</span> *<span class="title">next_free</span>;</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Number of threads attached to this arena.  0 if the arena is on</span></span><br><span class="line"><span class="comment">     the free list.  Access to this field is serialized by</span></span><br><span class="line"><span class="comment">     free_list_lock in arena.c.  */</span></span><br><span class="line">  INTERNAL_SIZE_T attached_threads;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Memory allocated from the system in this arena.  */</span></span><br><span class="line">  INTERNAL_SIZE_T system_mem;</span><br><span class="line">  INTERNAL_SIZE_T max_system_mem;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>​    bit通过下面的宏被设置，idx指定的位置为1，其他位为0 。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> idx2bit(i)       ((1U &lt;&lt; ((i) &amp; ((1U &lt;&lt; BINMAPSHIFT) - 1))))</span></span><br></pre></td></tr></table></figure>

<p>​    如果bit大于map，则map为0，map为0，说明当前bin中没有空闲chunk，所以去遍历bitmap的下一个block，直到找到一个不为0，或者遍历完才结束。</p>
<p>​    在退出循环遍历后，设置bin 指向block 的第一个bit 对应的bin，并将bit 为1，    表示该block中bit 1 对应的bin，这个bin 中如果有空闲chunk，该chunk 的大小一定满足要求。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BINMAPSHIFT      5</span></span><br></pre></td></tr></table></figure>

<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (;; )</span><br><span class="line">       &#123;</span><br><span class="line">         <span class="comment">/* Skip rest of block if there are no more set bits in this block.  */</span></span><br><span class="line">         <span class="keyword">if</span> (<span class="built_in">bit</span> &gt; <span class="built_in">map</span> || <span class="built_in">bit</span> == <span class="number">0</span>)</span><br><span class="line">           &#123;</span><br><span class="line">             <span class="keyword">do</span></span><br><span class="line">               &#123;</span><br><span class="line">                 <span class="keyword">if</span> (++block &gt;= BINMAPSIZE) <span class="comment">/* out of bins */</span></span><br><span class="line">                   <span class="keyword">goto</span> use_top;			<span class="comment">//走top chunk的逻辑</span></span><br><span class="line">               &#125;</span><br><span class="line">             <span class="keyword">while</span> ((<span class="built_in">map</span> = av-&gt;binmap[block]) == <span class="number">0</span>); <span class="comment">//取到下一个block的map</span></span><br><span class="line"></span><br><span class="line">             bin = bin_at (av, (block &lt;&lt; BINMAPSHIFT));</span><br><span class="line">             <span class="built_in">bit</span> = <span class="number">1</span>;</span><br><span class="line">           &#125;</span><br></pre></td></tr></table></figure>

<p>​    这段逻辑，是遍历一个block里所有的bin，因为map是非0的，所以找到bit不为0就退出循环，那么这个bit对应bin中一定有空闲chunk。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Advance to bin with set bit. There must be one. */</span></span><br><span class="line">        <span class="keyword">while</span> ((<span class="built_in">bit</span> &amp; <span class="built_in">map</span>) == <span class="number">0</span>)</span><br><span class="line">          &#123;</span><br><span class="line">            bin = next_bin (bin);</span><br><span class="line">            <span class="built_in">bit</span> &lt;&lt;= <span class="number">1</span>;</span><br><span class="line">            assert (<span class="built_in">bit</span> != <span class="number">0</span>);</span><br><span class="line">          &#125;</span><br></pre></td></tr></table></figure>

<p>​    获取这个bin的最后一个chunk即victim，如果最后一个chunk和链表头指针相同，那么说明这个链表中没有空chunk，这个时候就先把之前bit清零，然后到下一个bin中，</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Inspect the bin. It is likely to be non-empty */</span></span><br><span class="line">        victim = last (bin);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/*  If a false alarm (empty bin), clear the bit. */</span></span><br><span class="line">        <span class="keyword">if</span> (victim == bin)</span><br><span class="line">          &#123;</span><br><span class="line">            av-&gt;binmap[block] = <span class="built_in">map</span> &amp;= ~<span class="built_in">bit</span>; <span class="comment">/* Write through */</span></span><br><span class="line">            bin = next_bin (bin);</span><br><span class="line">            <span class="built_in">bit</span> &lt;&lt;= <span class="number">1</span>;</span><br><span class="line">          &#125;</span><br></pre></td></tr></table></figure>

<p>​    如果不相同，那么先的到victim的size，然后和之前的逻辑类似，计算分割后的大小remainder_size，然后使用unlink宏去把victim从链表中解链出来。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">else</span></span><br><span class="line">          &#123;</span><br><span class="line">            <span class="built_in">size</span> = chunksize (victim);</span><br><span class="line"></span><br><span class="line">            <span class="comment">/*  We know the first chunk in this bin is big enough to use. */</span></span><br><span class="line">            assert ((<span class="keyword">unsigned</span> <span class="keyword">long</span>) (<span class="built_in">size</span>) &gt;= (<span class="keyword">unsigned</span> <span class="keyword">long</span>) (nb));</span><br><span class="line"></span><br><span class="line">            remainder_size = <span class="built_in">size</span> - nb;</span><br><span class="line"></span><br><span class="line">            <span class="comment">/* unlink */</span></span><br><span class="line">            unlink (av, victim, bck, fwd);</span><br></pre></td></tr></table></figure>

<p>​    这里判断切割后的大小并针对不同的大小做不同的处理。</p>
<ol>
<li>如果切割剩余大小比MINSIZE小，那么就应该把整个chunk分给用户，之后就设置对应的标志位，之后就是返回的工作了；</li>
<li>如果比MINSIZE大，就要分割了。分割剩下的这块，要作为新的chunk加入unsorted bin。</li>
</ol>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Exhaust */</span></span><br><span class="line">           <span class="keyword">if</span> (remainder_size &lt; MINSIZE)</span><br><span class="line">             &#123;</span><br><span class="line">               set_inuse_bit_at_offset (victim, <span class="built_in">size</span>);</span><br><span class="line">               <span class="keyword">if</span> (av != &amp;main_arena)</span><br><span class="line">                 victim-&gt;<span class="built_in">size</span> |= NON_MAIN_ARENA;</span><br><span class="line">             &#125;</span><br><span class="line"></span><br><span class="line">           <span class="comment">/* Split */</span></span><br><span class="line">           <span class="keyword">else</span></span><br><span class="line">             &#123;</span><br><span class="line">               remainder = chunk_at_offset (victim, nb);</span><br><span class="line"></span><br><span class="line">               <span class="comment">/* We cannot assume the unsorted list is empty and therefore</span></span><br><span class="line"><span class="comment">                  have to perform a complete insert here.  */</span></span><br><span class="line">               bck = unsorted_chunks (av);</span><br><span class="line">               fwd = bck-&gt;fd;</span><br><span class="line"><span class="keyword">if</span> (__glibc_unlikely (fwd-&gt;bk != bck))</span><br><span class="line">                 &#123;</span><br><span class="line">                   errstr = <span class="string">"malloc(): corrupted unsorted chunks 2"</span>;</span><br><span class="line">                   <span class="keyword">goto</span> errout;</span><br><span class="line">                 &#125;</span><br><span class="line">               <span class="comment">//添加到第一个位置</span></span><br><span class="line">               remainder-&gt;bk = bck;</span><br><span class="line">               remainder-&gt;fd = fwd;</span><br><span class="line">               bck-&gt;fd = remainder;</span><br><span class="line">               fwd-&gt;bk = remainder;</span><br></pre></td></tr></table></figure>

<p>​    如果整个剩余的chunk是small bin，那么就要把分配区的last remainder 设置为这个chunk；如果是large bin，要把<code>fd_nextsize</code>和<code>bk_nextsize</code>置NULL，然后和之前对large bin处理的逻辑一样，设置head、foot的标志位。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* advertise as last remainder */</span></span><br><span class="line">               <span class="keyword">if</span> (in_smallbin_range (nb))</span><br><span class="line">                 av-&gt;last_remainder = remainder;</span><br><span class="line">               <span class="keyword">if</span> (!in_smallbin_range (remainder_size))</span><br><span class="line">                 &#123;</span><br><span class="line">                   remainder-&gt;fd_nextsize = <span class="literal">NULL</span>;</span><br><span class="line">                   remainder-&gt;bk_nextsize = <span class="literal">NULL</span>;</span><br><span class="line">                 &#125;</span><br><span class="line">               set_head (victim, nb | PREV_INUSE |</span><br><span class="line">                         (av != &amp;main_arena ? NON_MAIN_ARENA : <span class="number">0</span>));</span><br><span class="line">               set_head (remainder, remainder_size | PREV_INUSE);</span><br><span class="line">               set_foot (remainder, remainder_size);</span><br><span class="line">             &#125;</span><br></pre></td></tr></table></figure>

<p>​    最后逻辑很简单，调用<code>chunk2mem</code>的到可用的内存指针，并返回给用户。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">check_malloced_chunk (av, victim, nb);</span><br><span class="line">           <span class="keyword">void</span> *p = chunk2mem (victim);</span><br><span class="line">           alloc_perturb (p, bytes);</span><br><span class="line">           <span class="keyword">return</span> p;</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br></pre></td></tr></table></figure>



<h6 id="5-top-chunk"><a href="#5-top-chunk" class="headerlink" title="5.top chunk"></a>5.top chunk</h6><p>​    这部分是在前面所有分配都失败的情况下才会到的逻辑，即fastbin 、small bin、large bin 都没有分配到所需要的chunk，就会从当前分配实例的top chunk直接分配内存，代码如下</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">use_top:</span><br><span class="line">     <span class="comment">/*</span></span><br><span class="line"><span class="comment">        If large enough, split off the chunk bordering the end of memory</span></span><br><span class="line"><span class="comment">        (held in av-&gt;top). Note that this is in accord with the best-fit</span></span><br><span class="line"><span class="comment">        search rule.  In effect, av-&gt;top is treated as larger (and thus</span></span><br><span class="line"><span class="comment">        less well fitting) than any other available chunk since it can</span></span><br><span class="line"><span class="comment">        be extended to be as large as necessary (up to system</span></span><br><span class="line"><span class="comment">        limitations).</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">        We require that av-&gt;top always exists (i.e., has size &gt;=</span></span><br><span class="line"><span class="comment">        MINSIZE) after initialization, so if it would otherwise be</span></span><br><span class="line"><span class="comment">        exhausted by current request, it is replenished. (The main</span></span><br><span class="line"><span class="comment">        reason for ensuring it exists is that we may need MINSIZE space</span></span><br><span class="line"><span class="comment">        to put in fenceposts in sysmalloc.)</span></span><br><span class="line"><span class="comment">      */</span></span><br><span class="line"></span><br><span class="line">     victim = av-&gt;top;</span><br><span class="line">     <span class="built_in">size</span> = chunksize (victim);</span><br><span class="line"></span><br><span class="line">     <span class="keyword">if</span> ((<span class="keyword">unsigned</span> <span class="keyword">long</span>) (<span class="built_in">size</span>) &gt;= (<span class="keyword">unsigned</span> <span class="keyword">long</span>) (nb + MINSIZE))</span><br><span class="line">       &#123;</span><br><span class="line">         remainder_size = <span class="built_in">size</span> - nb;</span><br><span class="line">         remainder = chunk_at_offset (victim, nb);</span><br><span class="line">         av-&gt;top = remainder;</span><br><span class="line">         set_head (victim, nb | PREV_INUSE |</span><br><span class="line">                   (av != &amp;main_arena ? NON_MAIN_ARENA : <span class="number">0</span>));</span><br><span class="line">         set_head (remainder, remainder_size | PREV_INUSE);</span><br><span class="line"></span><br><span class="line">         check_malloced_chunk (av, victim, nb);</span><br><span class="line">         <span class="keyword">void</span> *p = chunk2mem (victim);</span><br><span class="line">         alloc_perturb (p, bytes);</span><br><span class="line">         <span class="keyword">return</span> p;</span><br><span class="line">       &#125;</span><br></pre></td></tr></table></figure>

<p>​    首先，获取到top chunk，然后获取top chunk的size，接着判断size和要分配的大小nb，如果size大于我们要分配的大小nb，那就直接从top chunk中分割，的到victim，分割剩余部分作为新的top chunk，设置victim的一些标志位之后，调用<code>chunk2mem()</code>的到可用内存指针并且返回给用户。</p>
<p>​    一点小细节，因为top chunk需要MINSIZE 的空间来作为fencepost，所以大小比较的时候要加个MINSIZE；所以在分割完成之后并不用去设置foot。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* When we are using atomic ops to free fast chunks we can get</span></span><br><span class="line"><span class="comment">   here for all block sizes.  */</span></span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (have_fastchunks (av))</span><br><span class="line">  &#123;</span><br><span class="line">    malloc_consolidate (av);</span><br><span class="line">    <span class="comment">/* restore original bin index */</span></span><br><span class="line">    <span class="keyword">if</span> (in_smallbin_range (nb))</span><br><span class="line">      idx = smallbin_index (nb);</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      idx = largebin_index (nb);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<p>​    如果还是没从top chunk中分配到，判断当前分配区中是否有fast bins中是否有chunk，有的话就合并到unsorted bin中，接着判断，在small bin范围内，就再次设置idx，进到最外层循环，再来一次，相对应的，large bin范围内也是一样，设置idx，再到最外层循环。</p>
<h6 id="6-sysmalloc"><a href="#6-sysmalloc" class="headerlink" title="6.sysmalloc"></a>6.sysmalloc</h6><p>​    在之前的分配策略都没办法分配到我们想要的内存的时候，就会走到这里。这里直接调用了<code>sycmalloc()</code>去分配，其实就是使用了<code>mmap()</code>直接映射，当然这个函数不可能这么简单，他对不同情况做了不同的处理。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">      <span class="comment">/*</span></span><br><span class="line"><span class="comment">         Otherwise, relay to handle system-dependent cases</span></span><br><span class="line"><span class="comment">       */</span></span><br><span class="line">      <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">          <span class="keyword">void</span> *p = sysmalloc (nb, av);</span><br><span class="line">          <span class="keyword">if</span> (p != <span class="literal">NULL</span>)</span><br><span class="line">            alloc_perturb (p, bytes);</span><br><span class="line">          <span class="keyword">return</span> p;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="2-sysmalloc-分析"><a href="#2-sysmalloc-分析" class="headerlink" title="2. sysmalloc 分析"></a>2. sysmalloc 分析</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">void</span> * </span><br><span class="line">  sysmalloc (INTERNAL_SIZE_T nb, mstate av)</span><br></pre></td></tr></table></figure>






<pre><code>为了治疗拖延症，所以把过程记录在博客上，慢慢更新...</code></pre>
      
    </div>
    
  </div>
  
    
    <div class="copyright">
        <p><span>本文标题:</span><a href="/2016/11/21/Have-fun-with-glibc%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/">Have fun with glibc内存管理</a></p>
        <p><span>文章作者:</span><a href="/" title="访问 muhe 的个人博客">muhe</a></p>
        <p><span>发布时间:</span>2016年11月21日 - 20时38分</p>
        <p><span>最后更新:</span>2016年11月25日 - 17时45分</p>
        <p>
            <span>原始链接:</span><a class="post-url" href="/2016/11/21/Have-fun-with-glibc%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/" title="Have fun with glibc内存管理">http://o0xmuhe.me/2016/11/21/Have-fun-with-glibc%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</a>
            <span class="copy-path" data-clipboard-text="原文: http://o0xmuhe.me/2016/11/21/Have-fun-with-glibc%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/　　作者: muhe" title="点击复制文章链接"><i class="fa fa-clipboard"></i></span>
            <script src="/js/clipboard.min.js"></script>
            <script> var clipboard = new Clipboard('.copy-path'); </script>
        </p>
        <p>
            <span>许可协议:</span><i class="fa fa-creative-commons"></i> <a rel="license noopener" href="http://creativecommons.org/licenses/by-nc-sa/3.0/cn/" target="_blank" title="中国大陆 (CC BY-NC-SA 3.0 CN)" target = "_blank">"署名-非商用-相同方式共享 3.0"</a> 转载请保留原文链接及作者。
        </p>
    </div>



<nav id="article-nav">
  
    <a href="/2016/11/25/PlaidCTF-2016-butterfly/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption"><</strong>
      <div class="article-nav-title">
        
          PlaidCTF 2016 butterfly
        
      </div>
    </a>
  
  
    <a href="/2016/11/10/linux-%E4%B8%8B%E8%B5%B7shell%E5%A4%B1%E8%B4%A5%E7%9A%84%E5%88%86%E6%9E%90/" id="article-nav-older" class="article-nav-link-wrap">
      <div class="article-nav-title">linux 下起shell失败的分析</div>
      <strong class="article-nav-caption">></strong>
    </a>
  
</nav>

  
</article>

    <div id="toc" class="toc-article">
    <strong class="toc-title">文章目录</strong>
    <ol class="toc"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-malloc-分析"><span class="toc-number">1.</span> <span class="toc-text">1.malloc 分析</span></a><ol class="toc-child"><li class="toc-item toc-level-6"><a class="toc-link" href="#1-概述"><span class="toc-number">1.0.1.</span> <span class="toc-text">1.概述</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#2-fastbin"><span class="toc-number">1.0.2.</span> <span class="toc-text">2.fastbin</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#3-small-bin"><span class="toc-number">1.0.3.</span> <span class="toc-text">3.small bin</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#4-large-bin"><span class="toc-number">1.0.4.</span> <span class="toc-text">4.large bin</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#5-top-chunk"><span class="toc-number">1.0.5.</span> <span class="toc-text">5.top chunk</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#6-sysmalloc"><span class="toc-number">1.0.6.</span> <span class="toc-text">6.sysmalloc</span></a></li></ol></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-sysmalloc-分析"><span class="toc-number">2.</span> <span class="toc-text">2. sysmalloc 分析</span></a></li></ol>
</div>
<input type="button" id="tocButton" value="隐藏目录"  title="点击按钮隐藏或者显示文章目录">

<script src="https://7.url.cn/edu/jslib/comb/require-2.1.6,jquery-1.9.1.min.js"></script>
<script>
    var valueHide = "隐藏目录";
    var valueShow = "显示目录";

    if ($(".left-col").is(":hidden")) {
        $("#tocButton").attr("value", valueShow);
    }
    $("#tocButton").click(function() {
        if ($("#toc").is(":hidden")) {
            $("#tocButton").attr("value", valueHide);
            $("#toc").slideDown(320);
        }
        else {
            $("#tocButton").attr("value", valueShow);
            $("#toc").slideUp(350);
        }
    })
    if ($(".toc").length < 1) {
        $("#toc, #tocButton").hide();
    }
</script>





<div class="bdsharebuttonbox">
	<a href="#" class="fx fa-weibo bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a>
	<a href="#" class="fx fa-weixin bds_weixin" data-cmd="weixin" title="分享到微信"></a>
	<a href="#" class="fx fa-qq bds_sqq" data-cmd="sqq" title="分享到QQ好友"></a>
	<a href="#" class="fx fa-facebook-official bds_fbook" data-cmd="fbook" title="分享到Facebook"></a>
	<a href="#" class="fx fa-twitter bds_twi" data-cmd="twi" title="分享到Twitter"></a>
	<a href="#" class="fx fa-linkedin bds_linkedin" data-cmd="linkedin" title="分享到linkedin"></a>
	<a href="#" class="fx fa-files-o bds_copy" data-cmd="copy" title="分享到复制网址"></a>
</div>
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"2","bdSize":"24"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>




    
        <section id="comments">
  <div id="disqus_thread"></div>
    <script type="text/javascript">
    /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
    var disqus_shortname = 'o0xmuhe'; // required: replace example with your forum shortname

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function() {
      var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
      dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
      (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
  </script>
  <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" target="_blank" rel="noopener">comments powered by Disqus.</a></noscript>
</section>
    



    <div class="scroll" id="post-nav-button">
        
            <a href="/2016/11/25/PlaidCTF-2016-butterfly/" title="上一篇: PlaidCTF 2016 butterfly">
                <i class="fa fa-angle-left"></i>
            </a>
        
        <a title="文章列表"><i class="fa fa-bars"></i><i class="fa fa-times"></i></a>
        
            <a href="/2016/11/10/linux-%E4%B8%8B%E8%B5%B7shell%E5%A4%B1%E8%B4%A5%E7%9A%84%E5%88%86%E6%9E%90/" title="下一篇: linux 下起shell失败的分析">
                <i class="fa fa-angle-right"></i>
            </a>
        
    </div>
    <ul class="post-list"><li class="post-list-item"><a class="post-list-link" href="/2019/11/15/frida-gum%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/">frida-gum代码阅读笔记</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/10/24/Linux-Kernel-%E7%BC%96%E8%AF%91%E8%B8%A9%E5%9D%91/">Linux Kernel 编译踩坑</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/10/17/Debug-macOS-Kernel/">Debug macOS Kernel</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/09/26/Snell-auto-install-cript/">Snell auto install cript</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/09/20/macOS-IPC-Study-basic-2/">macOS IPC Study Notes</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/09/09/Uninitialised-Objective-C-Pointer-Vulnerability-Analysis-CVE-2018-4196/">Uninitialised Objective-C Pointer Vulnerability Analysis (CVE-2018-4196)</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/09/02/CVE-2019-8604-analysis/">CVE-2019-8604 analysis</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/08/22/Bindiff5-0-Could-not-create-file-handler-fix/">Bindiff5.0 Could not create file handler fix</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/08/20/macOS-IPC-Study-basic/">macOS IPC Study basic</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/08/14/Adobe-Acrobat-Reader-getUIPerms-setUIPerms-Unicode-String-Out-of-bound-Read/">Adobe Acrobat Reader getUIPerms/setUIPerms  Unicode String Out-of-bound Read</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/08/10/Apple-IPC-DO-Basic/">Apple IPC : DO Basic</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/07/16/Adobe-Acrobat-DC-Pro-touchup-UaF/">Adobe Acrobat DC Pro touchup UaF</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/07/09/IDA%E8%87%AA%E5%8A%A8%E5%8C%96%E5%88%86%E6%9E%90/">IDA自动化分析</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/06/19/CVE-2017-2541-XGetWindowMovementGroup-stackoverflow/">CVE-2017-2541 __XGetWindowMovementGroup stackoverflow</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/06/19/CVE-2017-2540-XGetConnectionPSN-info-leak/">CVE-2017-2540 _XGetConnectionPSN info leak</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/06/14/find-macOS-service-and-it-s-plist-file/">find macOS service and it's plist file</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/05/15/Adobe-Acrobat-DC-Pro-OOB-CVE-2019-7813/">Adobe Acrobat DC Pro OOB(CVE-2019-7813)</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/05/10/macOS-on-ESXi/">macOS on ESXi</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/04/20/CVE-2017-2547-%E5%88%86%E6%9E%90/">CVE-2017-2547 分析</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/04/17/NULL/">NULL</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/04/12/CVE-2019-7125-PoC/">CVE-2019-7125 PoC</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/04/06/CVE-2018-4990-analysis/">CVE-2018-4990 analysis</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/04/06/CVE-2016-4622-analysis/">CVE-2016-4622  analysis</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/03/24/CVE-2017-2536-analysis/">CVE-2017-2536 analysis</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/03/12/CVE-2018-12794-%E5%88%86%E6%9E%90/">CVE-2018-12794 分析</a></li><li class="post-list-item"><a class="post-list-link" href="/2019/01/04/%E4%BD%BF%E7%94%A8Frida%E8%BE%85%E5%8A%A9%E9%80%86%E5%90%91/">使用Frida辅助逆向</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/12/31/Webkit%E7%BC%96%E8%AF%91%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/">Webkit编译踩坑记录</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/12/25/%E9%80%86%E5%90%91%E5%8D%8F%E4%BD%9C%E4%B9%8BIDA%E6%8F%92%E4%BB%B6IDArling/">逆向协作之IDA插件IDArling</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/12/13/%E7%94%B1CVE-2018-12831%E5%BC%95%E5%8F%91%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%9D%E8%80%83/">由CVE-2018-12831引发的一些思考</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/11/18/TFC%E6%B8%B8%E8%AE%B0/">TFC游记</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/11/08/Hello-PANDA/">Hello PANDA</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/11/07/UAF-analysis-using-pykd/">UAF analysis : using pykd</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/10/05/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E5%9F%B9%E5%85%BB%E8%AE%A1%E5%88%92/">代码审计培养计划</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/08/13/%E9%A3%9E%E6%89%AC%E5%8E%86%E9%99%A9%E8%AE%B0/">飞扬历险记</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/06/16/linux-code-inject/">linux code inject</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/06/16/%E6%AF%94%E8%B5%9B%E8%BF%90%E7%BB%B4%E6%9D%82%E8%AE%B0/">比赛运维杂记</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/06/09/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB-IFuzzer-An-Evolutionary-Interpreter-Fuzzer-using-Genetic-Programming/">论文阅读<IFuzzer: An Evolutionary Interpreter Fuzzer using Genetic Programming></a></li><li class="post-list-item"><a class="post-list-link" href="/2018/06/03/%E9%81%97%E4%BC%A0%E7%AE%97%E6%B3%95%E5%88%9D%E7%AA%A5/">遗传算法初窥</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/05/29/Antlr4%E5%88%9D%E4%BD%93%E9%AA%8C/">Antlr4初体验</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/04/19/mips%E7%A8%8B%E5%BA%8F%E8%B0%83%E8%AF%95%E7%8E%AF%E5%A2%83%E6%8A%98%E8%85%BE/">mips程序调试环境折腾</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/03/14/%E6%8B%AF%E6%95%91macOS-High-sierra%E7%9A%84%E7%A1%AC%E7%9B%98%E7%A9%BA%E9%97%B4/">拯救macOS High sierra的硬盘空间</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/02/16/Symbolic-Execution%E5%AD%A6%E4%B9%A0/">Symbolic Execution学习</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/02/11/LL-LR-SLR-LALR%E5%82%BB%E5%82%BB%E5%88%86%E4%B8%8D%E6%B8%85/">LL LR SLR LALR傻傻分不清</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/20/compiler%E5%AD%A6%E4%B9%A0/">compiler学习</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/15/Unicorn-Engine%E5%88%9D%E4%BD%93%E9%AA%8C/">Unicorn Engine初体验</a></li><li class="post-list-item"><a class="post-list-link" href="/2018/01/06/flex-bison%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/">flex_bison读书笔记</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/12/30/Python%E6%8C%87%E5%AE%9A%E6%A6%82%E7%8E%87%E8%8E%B7%E5%8F%96%E9%9A%8F%E6%9C%BA%E5%85%83%E7%B4%A0/">Python指定概率获取随机元素</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/10/01/Hello-World%E5%8D%87%E7%BA%A7%E7%89%88/">Hello World升级版</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/07/13/babydriver-writeup/">babydriver writeup</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/07/05/OpenGrok%E6%90%AD%E5%BB%BA/">OpenGrok搭建</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/30/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86%E5%AD%A6%E4%B9%A0/">编译原理学习</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/28/TrendMicro-CTF-2017-Reverse300/">TrendMicro CTF 2017 Reverse300</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/06/19/Final/">Final</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/05/29/pwnhub%E6%9D%AFCUIT%E7%AC%AC%E5%8D%81%E4%B8%89%E5%B1%8A%E6%A0%A1%E8%B5%9Bpwn%E5%87%BA%E9%A2%98%E5%8F%8A%E8%BF%90%E7%BB%B4%E5%BF%83%E5%BE%97/">pwnhub杯CUIT第十三届校赛pwn出题及运维心得</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/05/08/SSCTF-2017%E9%83%A8%E5%88%86Writeup/">SSCTF-2017部分Writeup</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/04/22/360%E6%98%A5%E7%A7%8BCTF-pwn/">360春秋CTF--pwn</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/04/06/Linux-Kernel-Exploit-4-beginners/">Linux Kernel Exploit 4 beginners</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/03/15/NJCTF-2017%E9%83%A8%E5%88%86wp/">NJCTF-2017部分wp</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/03/06/SECCON-2016-jmper/">SECCON-2016 jmper</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/03/04/codegate2017-angrybird/">codegate2017-angrybird</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/02/27/LLVM-Study-Log/">LLVM Study Log</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/02/16/ichunqiu-CTF-2017-2/">ichunqiu-CTF-2017-2</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/02/08/Adding-your-own-syscall-in-linux-kernel/">Adding your own syscall in linux kernel</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/02/04/Windows-Kernel-Exploit-Study-3/">Windows-Kernel-Exploit-Study(3)</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/01/30/Linux%20socket%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1%E5%8F%8A%E5%BA%94%E7%94%A8/">Linux socket进程间通信及应用</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/01/28/%E9%97%B2%E8%A8%80%E7%A2%8E%E8%AF%AD/">闲言碎语</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/01/22/Have-fun-with-Blind-ROP/">Have fun with Blind ROP</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/01/20/Windows-Kernel-Exploit-Study-2/">Windows Kernel Exploit Study(2)</a></li><li class="post-list-item"><a class="post-list-link" href="/2017/01/19/Windows-Kernel-Exploit-Study-1/">Windows Kernel Exploit Study(1)</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/12/24/what-DynELF-does-basically/">what DynELF does basically</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/12/17/fuzzing-with-peach-Just-a-toy/">fuzzing with peach(Just a toy)</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/11/25/PlaidCTF-2016-butterfly/">PlaidCTF 2016 butterfly</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/11/21/Have-fun-with-glibc%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/">Have fun with glibc内存管理</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/11/10/linux-%E4%B8%8B%E8%B5%B7shell%E5%A4%B1%E8%B4%A5%E7%9A%84%E5%88%86%E6%9E%90/">linux 下起shell失败的分析</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/11/07/Baiudu%E6%9D%AF-pwn%E4%B8%93%E5%9C%BA%E8%AE%B0%E5%BD%95/">Baiudu杯 pwn专场记录</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/10/29/how-to-compile-WinAFL/">how to compile WinAFL</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/10/25/yocto-writeup/">yocto writeup</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/10/11/HITCON-2016-Quals-SecretHolder/">HITCON-2016-Quals-SecretHolder</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/09/27/BCTF-cloud/">BCTF--cloud</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/09/24/%E4%B8%80%E4%BA%9B%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%E9%81%87%E5%88%B0%E7%9A%84%E5%9D%91-%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0/">一些环境配置遇到的坑(持续更新)</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/09/16/Malloc-Maleficarum-%E5%A4%8D%E7%9B%98/">Malloc-Maleficarum-复盘</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/08/26/%E5%88%9D%E8%AF%95winafl/">初试winafl</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/08/14/pwnable-kr-alloca/">pwnable.kr -- alloca</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/08/01/%E7%AE%80%E5%8D%95%E7%9A%84%E5%B0%9D%E8%AF%95angr/">简单的尝试angr</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/06/29/%E7%AC%AC%E4%B8%80%E4%B8%AAandroid-cm%E8%B0%83%E8%AF%95%E5%88%86%E6%9E%90/">第一个android cm调试分析</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/06/29/install-gef/">install gef</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/04/30/cctf-pwn350/">cctf pwn350</a></li><li class="post-list-item"><a class="post-list-link" href="/2016/02/15/heap-vuln-unlink/">heap vuln -- unlink</a></li><li class="post-list-item"><a class="post-list-link" href="/2015/12/02/format-string-with-stack-frame/">format string with stack frame</a></li><li class="post-list-item"><a class="post-list-link" href="/2015/11/16/RCTF-PWN200/">RCTF -- PWN200</a></li><li class="post-list-item"><a class="post-list-link" href="/2015/11/05/dragon/">dragon</a></li></ul>
    <script src="https://7.url.cn/edu/jslib/comb/require-2.1.6,jquery-1.9.1.min.js"></script>
    <script>
        $(".post-list").addClass("toc-article");
        $(".post-list-item a").attr("target","_blank");
        $("#post-nav-button > a:nth-child(2)").click(function() {
            $(".fa-bars, .fa-times").toggle();
            $(".post-list").toggle(300);
            if ($(".toc").length > 0) {
                $("#toc, #tocButton").toggle(200, function() {
                    if ($(".switch-area").is(":visible")) {
                        $("#tocButton").attr("value", valueHide);
                        }
                    })
            }
            else {
            }
        })
    </script>



    <script>
        
    </script>
</div>
      <footer id="footer">
    <div class="outer">
        <div id="footer-info">
            <div class="footer-left">
                &copy; 2019 muhe
            </div>
            <div class="footer-right">
                <a href="http://hexo.io/" target="_blank">Hexo</a>  Theme <a href="https://github.com/luuman/hexo-theme-spfk" target="_blank">spfk</a> by luuman
            </div>
        </div>
        
            <div class="visit">
                
                    <span id="busuanzi_container_site_pv" style='display:none'>
                        <span id="site-visit" >访客数量: 
                            <span id="busuanzi_value_site_uv"></span>
                        </span>
                    </span>
                
                
                    <span>, </span>
                
                
                    <span id="busuanzi_container_page_pv" style='display:none'>
                        <span id="page-visit">本页阅读量: 
                            <span id="busuanzi_value_page_pv"></span>
                        </span>
                    </span>
                
            </div>
        
    </div>
</footer>

    </div>
    <script src="https://7.url.cn/edu/jslib/comb/require-2.1.6,jquery-1.9.1.min.js"></script>
<script src="/js/main.js"></script>

    <script>
        $(document).ready(function() {
            var backgroundnum = 24;
            var backgroundimg = "url(/background/bg-x.jpg)".replace(/x/gi, Math.ceil(Math.random() * backgroundnum));
            $("#mobile-nav").css({"background-image": backgroundimg,"background-size": "cover","background-position": "center"});
            $(".left-col").css({"background-image": backgroundimg,"background-size": "cover","background-position": "center"});
        })
    </script>





<div class="scroll" id="scroll">
    <a href="#"><i class="fa fa-arrow-up"></i></a>
    <a href="#comments"><i class="fa fa-comments-o"></i></a>
    <a href="#footer"><i class="fa fa-arrow-down"></i></a>
</div>
<script>
    $(document).ready(function() {
        if ($("#comments").length < 1) {
            $("#scroll > a:nth-child(2)").hide();
        };
    })
</script>

<script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js">
</script>

  <script language="javascript">
    $(function() {
        $("a[title]").each(function() {
            var a = $(this);
            var title = a.attr('title');
            if (title == undefined || title == "") return;
            a.data('title', title).removeAttr('title').hover(

            function() {
                var offset = a.offset();
                $("<div id=\"anchortitlecontainer\"></div>").appendTo($("body")).html(title).css({
                    top: offset.top - a.outerHeight() - 15,
                    left: offset.left + a.outerWidth()/2 + 1
                }).fadeIn(function() {
                    var pop = $(this);
                    setTimeout(function() {
                        pop.remove();
                    }, pop.text().length * 800);
                });
            }, function() {
                $("#anchortitlecontainer").remove();
            });
        });
    });
</script>


  </div>
</body>
</html>